package blazingbubble.network.game;

import blazingbubble.network.game.strategy.PlayerJoinedTeamStrategy;
import org.apache.log4j.Logger;

import java.net.SocketException;
import java.net.DatagramPacket;
import java.net.InetSocketAddress;

import spark.network.*;
import spark.network.protocol.*;
import moltencore.network.protocol.*;

/**
 * Demon handling the game networking.
 */
public class GameDemon extends Demon implements Runnable {
	private static Logger logger = Logger.getLogger(GameDemon.class);

	private GameDemonHandler handler;
	private GameStrategyFactory strategyFactory;

	public GameDemon(ServerConnection serverConnection, Sender sender, GameStrategyFactory strategyFactory) throws SocketException {
		super();
		handler = new GameDemonHandler(serverConnection, sender);
		setTimeAdjuster(handler);
		this.strategyFactory = strategyFactory;
	}

	public GameDemon(int queryPort, ServerConnection serverConnection, ServerSender sender, GameStrategyFactory strategyFactory) throws SocketException {
		super(queryPort);
		handler = new GameDemonHandler(serverConnection, sender);
		this.strategyFactory = strategyFactory;
	}

	public void setPreLoginResponseListener(IPreLoginResponseResultListener preLoginResponseListener) {
		handler.setPreLoginResponseListener(preLoginResponseListener);
	}

	@Override
	protected void processPacket(DatagramPacket packet, long receiveTime) {
		byte[] packetData = packet.getData();
		InetSocketAddress source = Util.extractInetSocketAddress(packet);
		switch(Base.getType(packetData)) {
			case Acknowledgement.TYPE:
				logger.debug("Received: Acknowledgement from " + source);
				handler.handle(Acknowledgement.create(packetData, receiveTime), source);
				break;
			case PreLoginResponse.TYPE:
				logger.debug("Received: PreLoginResponse from " + source);
				handler.handle(PreLoginResponse.create(packetData, receiveTime), source);
				break;
			case ClockSyncReq.TYPE:
				logger.debug("Received: ClockSyncReq from " + source);
				handler.handle(ClockSyncReq.create(packetData, receiveTime), source);
				break;
			case ClockAdjustNotice.TYPE:
				logger.debug("Received: ClockAdjustNotice from " + source);
				handler.handle(ClockAdjustNotice.create(packetData, receiveTime), source);
				break;
			case JoinGameResponse.TYPE:
				logger.debug("Received: JoinGameResponse from " + source);
				handler.handle(JoinGameResponse.create(packetData, receiveTime), source, strategyFactory.getJoinGameResponseStrategy());
				break;
			case PlayerJoinedGame.TYPE:
				logger.debug("Received: PlayerJoinedGame from " + source);
				handler.handle(PlayerJoinedGame.create(packetData, receiveTime), source, strategyFactory.getPlayerJoinedGameStrategy());
				break;
			case PlayerJoinedTeam.TYPE:
				logger.debug("Received: PlayerJoinedTeam from " + source);
				handler.handle(PlayerJoinedTeam.create(packetData, receiveTime), source, strategyFactory.getPlayerJoinedTeamStrategy());
				break;
			case StartGameResponse.TYPE:
				logger.debug("Received: StartGameResponse from " + source);
				handler.handle(StartGameResponse.create(packetData, receiveTime), source, strategyFactory.getStartGameResponseStrategy());
				break;
			case GameStartingNotification.TYPE:
				logger.debug("Received: GameStartingNotification from " + source);
				handler.handle(GameStartingNotification.create(packetData, receiveTime), source, strategyFactory.getGameStartingNotificationStrategy());
				break;
			case FieldLayout.TYPE:
				logger.debug("Received: FieldLayout from " + source);
				handler.handle(FieldLayout.create(packetData, receiveTime), source, strategyFactory.getFieldLayoutStrategy());
				break;
			case GameStarted.TYPE:
				logger.debug("Received: GameStarted from " + source);
				handler.handle(GameStarted.create(packetData, receiveTime), source, strategyFactory.getGameStartedStrategy());
				break;
			case CannonNewTargetDirection.TYPE:
				//logger.debug("Received: CannonNewTargetDirection from " + source);
				handler.handle(CannonNewTargetDirection.create(packetData, receiveTime), source, strategyFactory.getCannonNewTargetDirectionStrategy());
				break;
			case BubbleFixatedNotification.TYPE:
				logger.debug("Received: BubbleFixatedNotification from " + source);
				handler.handle(BubbleFixatedNotification.create(packetData, receiveTime), source, strategyFactory.getBubbleFixatedNotificationStrategy());
				break;
			case BubblePoppedNotification.TYPE:
				logger.debug("Received: BubbleFixatedNotification from " + source);
				handler.handle(BubblePoppedNotification.create(packetData, receiveTime), source, strategyFactory.getBubblePoppedNotificationStrategy());
				break;
			case BubbleNextNotification.TYPE:
				logger.debug("Received: BubbleNextNotification from " + source);
				handler.handle(BubbleNextNotification.create(packetData, receiveTime), source, strategyFactory.getBubbleNextNotificationStrategy());
				break;
			case BubbleMovingNotification.TYPE:
				logger.debug("Received: BubbleNextNotification from " + source);
				handler.handle(BubbleMovingNotification.create(packetData, receiveTime), source, strategyFactory.getBubbleFiredNotificationStrategy());
				break;
			case RowPushed.TYPE:
				logger.debug("Received: RowPushed from " + source);
				handler.handle(RowPushed.create(packetData, receiveTime), source, strategyFactory.getRowPushedStrategy());
				break;
			case PlayerScoreUpdate.TYPE:
				logger.debug("Received: PlayerScoreUpdate from " + source);
				handler.handle(PlayerScoreUpdate.create(packetData, receiveTime), source, strategyFactory.getPlayerScoreUpdateStrategy());
				break;
			case TimeLeft.TYPE:
				logger.debug("Received: TimeLeft from " + source);
				handler.handle(TimeLeft.create(packetData, receiveTime), source, strategyFactory.getTimeLeftStrategy());
				break;
			case GameEndedNotification.TYPE:
				logger.debug("Received: GameEndedNotification from " + source);
				handler.handle(GameEndedNotification.create(packetData, receiveTime), source, strategyFactory.getGameEndedNotificationStrategy());
				break;
			default:
				//TODO : when done with programming the protocol remove this warn message
				//unknown protocol type received, ignore it
				logger.warn("Unknown protocol type received " + Integer.toHexString(Base.getType(packet.getData())) + ". Forgot to handle this protocol type?");
				break;
		}
	}
}